﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharpGL;

namespace SharpGLWinformsApplication1
{
    /// <summary>
    /// The main form class.
    /// </summary>
    public partial class SharpGLForm : Form
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SharpGLForm"/> class.
        /// </summary>
        public SharpGLForm()
        {
            Rotation = 0;
            WheelScale = 60.0f;
            Z_angle = 0.25f;
            adX = adY = adZ = 0; 
            InitializeComponent();
        }


        /// <summary>
        /// Для камеры
        /// </summary>
        private float Rotation, SizeX, SizeY, SizeZ, WheelScale, Z_angle;    //Размеры объекта, положение камеры
        private double adX, adY, adZ;   //Прибавка к центру
        private int currY;
        private int currX;



        /// <summary>
        /// Handles the OpenGLDraw event of the openGLControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
        {
            //  Get the OpenGL object.
            OpenGL gl = openGLControl.OpenGL;

            //  Clear the color and depth buffer.
            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
            gl.PolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_LINE);
            //  Load the identity matrix.
            gl.LoadIdentity();
            gl.Color(0, 0, 0);
            gl.Begin(OpenGL.GL_QUADS);
            gl.Vertex(-10, -10, -10);
            gl.Vertex(-10, 10, -10);
            gl.Vertex(10, 10, -10);
            gl.Vertex(10, -10, -10);

            gl.Vertex(-10, -10, 10);
            gl.Vertex(-10, 10, 10);
            gl.Vertex(10, 10, 10);
            gl.Vertex(10, -10, 10);

            gl.Vertex(-10, -10, -10);
            gl.Vertex(-10, 10, -10);
            gl.Vertex(-10, 10, 10);
            gl.Vertex(-10, -10, 10);

            gl.Vertex(10, -10, -10);
            gl.Vertex(10, 10, -10);
            gl.Vertex(10, 10, 10);
            gl.Vertex(10, -10, 10);

            gl.Vertex(-10, -10, -10);
            gl.Vertex(10, -10, -10);
            gl.Vertex(10, -10, 10);
            gl.Vertex(-10, -10, 10);

            gl.Vertex(-10, 10, -10);
            gl.Vertex(10, 10, -10);
            gl.Vertex(10, 10, 10);
            gl.Vertex(-10, 10, 10);

            gl.End();

        }

        private void RefreshView()
        {
            OpenGL gl = openGLControl.OpenGL;

            //  Set the projection matrix.
            gl.MatrixMode(OpenGL.GL_PROJECTION);

            //  Load the identity.
            gl.LoadIdentity();
            gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);
            gl.LookAt(-Math.Sin(Rotation) * WheelScale * Math.Cos(Z_angle) + adX, -Math.Cos(Rotation) * WheelScale * Math.Cos(Z_angle) + adY, WheelScale * Math.Sin(Z_angle) + adZ, adX, adY, adZ, 0, 0, 1);

            //  Set the modelview matrix.
            gl.MatrixMode(OpenGL.GL_MODELVIEW);
        }
        //трехфлоатовый+альфаканал цвет из числа
        private float[] ARGBToRGBAFloatColor(int argb)
        {
            var blue = ((argb & 0x000000ff)) * 1.0f / 255.0f;
            var green = ((argb & 0x0000ff00) >> 8) * 1.0f / 255.0f;
            var red = ((argb & 0x00ff0000) >> 16) * 1.0f / 255.0f;
            var alpha = ((argb & 0xff000000) >> 24) * 1.0f / 255.0f;
            return new[] { red, green, blue, alpha };
        }
        /// <summary>
        /// Handles the OpenGLInitialized event of the openGLControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
        {
            //  TODO: Initialise OpenGL here.

            //  Get the OpenGL object.
            OpenGL gl = openGLControl.OpenGL;
            var clr = ARGBToRGBAFloatColor(this.BackColor.ToArgb());
            gl.ClearColor(clr[0], clr[1], clr[2], clr[3]);
        }

        /// <summary>
        /// Handles the Resized event of the openGLControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void openGLControl_Resized(object sender, EventArgs e)
        {
            //  TODO: Set the projection matrix here.

            //  Get the OpenGL object.
            //OpenGL gl = openGLControl.OpenGL;

            RefreshView();
        }
        private void openGLControl_MouseDown(object sender, MouseEventArgs e)
        {
            currX = e.X;
            currY = e.Y;
        }
        private void openGLControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button.HasFlag(MouseButtons.Right))
            {
                Rotation += (float)(e.X - currX) * 0.012f;
                Z_angle += (float)(e.Y - currY) * 0.012f;
                if (Z_angle > Math.PI * 0.95f / 2f) Z_angle = (float)Math.PI * 0.95f / 2f;
                if (Z_angle < -Math.PI * 0.95f / 2f) Z_angle = -(float)Math.PI * 0.95f / 2f;
                currX = e.X;
                currY = e.Y;
                RefreshView();
            }
            if (e.Button.HasFlag(MouseButtons.Left))
            {
                var AddsX = (float)(e.X - currX) * WheelScale / (float)openGLControl.Width;
                var AddsY = (float)(e.Y - currY) * WheelScale / (float)openGLControl.Height;
                adZ += AddsY;
                adX -= AddsX * Math.Cos(Rotation);// -AddsY * Math.Sin(Rotation);
                adY += AddsX * Math.Sin(Rotation);// -AddsY * Math.Cos(Rotation);
                currX = e.X;
                currY = e.Y;
                RefreshView();
            }
        }
        private void openGLControl_MouseWheel(object sender, MouseEventArgs e)
        {
            WheelScale *= (float)Math.Exp((double)(e.Delta) * 0.004);
            if (WheelScale > 80f) WheelScale = 80f;
            if (WheelScale < 0.1f) WheelScale = 0.1f;

            RefreshView();
        }

    }
}
